package study.activiti.d_processVariables;

import java.io.InputStream;
import java.util.Date;
import java.util.List;

import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricVariableInstance;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.junit.Test;

import com.sun.org.apache.bcel.internal.generic.NEW;

/**  
 * @Name: ProcessVariablesTest
 * @Description: 流程变量测试类：设置和获取流程变量
 * 流程变量的作用：
 * 		1、用来传递业务参数，如请假流程中请假天数、请假时间、请假原因等
 * 		2、指定连接（网关）完成任务（同意和拒绝）
 * 		3、动态指定任务的办理人
 * 流程变量的作用域：
 * 		流程变量的作用域范围是只对应一个流程实例。也就是说各个流程实例的流程变量是不相互影响的。
 * 		流程实例结束完成以后流程变量还保存在数据库中（存放到流程变量的历史表中）。
 * @Author: 李超
 * @Create Date: 2016-12-11
 */
public class ProcessVariablesTest {
	
	//流程引擎
	private ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine() ;
	
	/**  
	* @Name: delpoymentProcessDefinition_inputStream（方法的名称）
	* @Description: 部署流程定义文件（输入流加载资源文件）（方法的描述）
	* 输入流加载资源文件的三种方式
	* 		1、从classpath跟目录下加载指定名称的文件，不加斜杠
	* 		  InputStream in = this.getClass().getClassLoader().getResourceAsStream("test.bpmn") ;
	* 		2、从当前包下加载指定名称的文件
	* 		  InputStream in = this.getClass().getResourceAsStream("test.bpmn") ;
	* 		3、从classpath跟目录下加载指定名称的文件，加斜杠
	* 		  this.getClass().getResourceAsStream("/test.bpmn") ;
	* @Author: 李超（作者）
	* @Version: V1.00 （版本号）
	* @Create Date: 2016-12-11 （创建日期）
	* @Parameters: 无（方法的入参，如果没有，填写为“无”）
	* @Return: 无（返回值，如果没有，填写为“无”）
	*/
	@Test
	public void delpoymentProcessDefinition_inputStream() {
		//获取指定资源文件的输入流对象
		InputStream inputStreamBpmn = this.getClass().getResourceAsStream("/diagrams/processVariables.bpmn") ;
		InputStream inputStreamPng = this.getClass().getResourceAsStream("/diagrams/processVariables.png") ;
		Deployment deployment = processEngine.getRepositoryService() //与部署对象和流程定义相关的Service
					 .createDeployment() //创建部署对象
					 .name("部署流程的名称") //添加部署名称
					 .addInputStream("processVariables.bpmn", inputStreamBpmn) //使用资源文件的名称和输入流完成部署
					 .addInputStream("processVariables.png", inputStreamPng) //使用资源文件的名称和输入流完成部署
					 .deploy() ; //发布流程
		System.out.println("id[部署id]：" + deployment.getId()); 
		System.out.println("name[部署名称]：" + deployment.getName()); 
	}
	
	/**  
	* @Name: startProcessInstance（方法的名称）
	* @Description: 启动流程实例（方法的描述）
	* @Author: 李超（作者）
	* @Version: V1.00 （版本号）
	* @Create Date: 2016-12-11 （创建日期）
	* @Parameters: 无（方法的入参，如果没有，填写为“无”）
	* @Return: 无（返回值，如果没有，填写为“无”）
	*/
	@Test
	public void startProcessInstance() {
		//流程定义的key
		String processDefinitionKey = "processVariables" ;
		//启动流程定义
		ProcessInstance instance = processEngine.getRuntimeService() //与正在执行的流程实例和执行对象相关的service
					 .startProcessInstanceByKey(processDefinitionKey) ; //使用流程定义的key启动流程实例
		System.out.println("pid[流程实例id]:" + instance.getId());  //流程实例ID
		System.out.println("activitiId[流程定义id]:" + instance.getProcessDefinitionId()); //流程定义ID
	}
	
	/**  
	* @Name: setVariables（方法的名称）
	* @Description: 设置流程变量（方法的描述）’
	* 说明：setVariable()与setVariableLocal()方法的区别
	* 		1、setVariableLocal()代表与当前正在执行的任务绑定(正在执行的流程变量表中的taskId字段会有值)，任务完成之后将从正在执行的流程变量表中删除
	* 		2、setVariableLocal()将会覆盖低版本的流程变量记录，包括正在执行的流程变量表和历史的流程变量表
	* 一般请款下，直接使用setVariable()即可，如果有需求，可选择setVariableLocal()
	* @Author: 李超（作者）
	* @Version: V1.00 （版本号）
	* @Create Date: 2016-12-12 （创建日期）
	* @Parameters: 无（方法的入参，如果没有，填写为“无”）
	* @Return: 无（返回值，如果没有，填写为“无”）
	*/
	@Test
	public void setVariables() {
		//获取任务服务——与任务（正在执行）相关的service
		TaskService taskService = processEngine.getTaskService() ;
		//任务ID
		String taskId = "62504" ;
		//变量类型一：设置流程变量，使用基本数据类型
		//taskService.setVariableLocal(taskId, "请假天数", 3) ; 
		//taskService.setVariable(taskId, "请假日期", new Date()) ;
		//taskService.setVariable(taskId, "请假原因", "回家探亲") ;
		//变量类型二：设置流程变量，使用javaBean类型
		//注意：当一个javaBean(实现序列化)放置到流程变量中时，要求javabean的属性不能再发生变化，如果发生变化，在获取时，会抛出异常
		//解决办法：在Javabean中添加序列化ID同时实现序列化接口
		Person p = new Person(10, "翠花", "高中") ;
		taskService.setVariable(taskId, "人员信息（添加固定版本）", p) ;
		System.out.println("设置成功");
	}
	
	/**  
	* @Name: getVariables（方法的名称）
	* @Description: 获取流程变量（方法的描述）
	* @Author: 李超（作者）
	* @Version: V1.00 （版本号）
	* @Create Date: 2016-12-12 （创建日期）
	* @Parameters: 无（方法的入参，如果没有，填写为“无”）
	* @Return: 无（返回值，如果没有，填写为“无”）
	*/
	@Test
	public void getVariables() {
		//获取任务服务——与任务（正在执行）相关的service
		TaskService taskService = processEngine.getTaskService() ;
		//任务ID
		String taskId = "62504" ;
		//变量类型一：获取流程变量，使用基本数据类型
		//Integer days = (Integer) taskService.getVariable(taskId, "请假天数") ;
		//Date date = (Date) taskService.getVariable(taskId, "请假日期") ;
		//String reason = (String) taskService.getVariable(taskId, "请假原因") ;
		//System.out.println("请假天数：" + days);
		//System.out.println("请假日期：" + date);
		//System.out.println("请假原因：" + reason);
		//变量类型二：获取流程变量，使用javaBean类型
		Person person = (Person) taskService.getVariable(taskId, "人员信息（添加固定版本）") ;
		System.out.println(person);
	}
	
	/**  
	* @Name: setAndGetVariables（方法的名称）
	* @Description: 模拟设置和获取流程变量（方法的描述）
	* @Author: 李超（作者）
	* @Version: V1.00 （版本号）
	* @Create Date: 2016-12-12 （创建日期）
	* @Parameters: 无（方法的入参，如果没有，填写为“无”）
	* @Return: 无（返回值，如果没有，填写为“无”）
	*/
	public void setAndGetVariables() {
		//设置流程变量
		//方式一：通过RuntimeService——与流程实例和执行对象（正在执行）相关的Service
		//RuntimeService runtimeService = processEngine.getRuntimeService() ;
		//设置流程变量的值
		//方法一：使用执行对象id，和流程变量的名称，设置流程变量的值（一次只能设置一个变量值）
		//runtimeService.setVariable(executionId, variableName, value) ; 
		//方法二：使用执行对象id，和Map<流程变量的名称，流程变量的值>集合设置流程变量的值（一次可以设置多个变量值）
		//runtimeService.setVariables(executionId, Map<流程变量的名称，流程变量的值>) ;
		//方式三：启动流程实例的同时，可以设置流程变量，使用Map<流程变量的名称，流程变量的值>集合
		//runtimeService.startProcessInstanceById(executionId, Map<流程变量的名称，流程变量的值>) ;
		
		//方式二：通过TaskService——与任务（正在执行）相关的service
		//TaskService taskService = processEngine.getTaskService() ;
		//设置流程变量的值
		//方法一：使用任务id，和流程变量的名称，设置流程变量的值（一次只能设置一个变量值）
		//taskService.setVariable(taskId, variableName, value) ; 
		//方法二：使用任务id，和Map<流程变量的名称，流程变量的值>集合设置流程变量的值（一次可以设置多个变量值）
		//taskService.setVariables(taskId, Map<流程变量的名称，流程变量的值>) ;
		//方式三：完成任务的同时，设置流程变量，使用Map<流程变量的名称，流程变量的值>集合
		//taskService.complete(taskId, Map<流程变量的名称，流程变量的值>) ;
		
		//获取流程变量
		//方式一：通过RuntimeService——与流程实例和执行对象（正在执行）相关的Service
		//RuntimeService runtimeService = processEngine.getRuntimeService() ;
		//方法一：使用执行对象ID，流程变量名称，获取流程变量的值
		//runtimeService.getVariable(executionId, variableName) ;
		//方法二：使用执行对象ID获取所有的流程变量，返回Map<流程变量的名称，流程变量的值>集合
		//runtimeService.getVariable(executionId) ;
		//方法三：使用执行对象ID，Map<指定流程变量的名称>集合，获取Map<流程变量的值>集合
		//runtimeService.getVariable(executionId, Map<指定流程变量的名称>集合) ;
		
		//方式二：通过TaskService——与任务（正在执行）相关的service
		//TaskService taskService = processEngine.getTaskService() ;
		//方法一：使用任务id，流程变量名称，获取流程变量的值
		//runtimeService.getVariable(taskId, variableName) ;
		//方法二：使用任务id获取所有的流程变量，返回Map<流程变量的名称，流程变量的值>集合
		//runtimeService.getVariable(taskId) ;
		//方法三：使用任务id，Map<指定流程变量的名称>集合，获取Map<流程变量的值>集合
		//runtimeService.getVariable(taskId, Map<指定流程变量的名称>集合) ;
	}
	
	/**  
	* @Name: completeMyPersonTask（方法的名称）
	* @Description: 办理（完成）当前人的个人任务（方法的描述）
	* @Author: 李超（作者）
	* @Version: V1.00 （版本号）
	* @Create Date: 2016-12-12 （创建日期）
	* @Parameters: 无（方法的入参，如果没有，填写为“无”）
	* @Return: 无（返回值，如果没有，填写为“无”）
	*/
	@Test
	public void completeMyPersonTask() {
		//任务ID
		String taskId = "70002" ;
		processEngine.getTaskService().complete(taskId) ;
		System.out.println("完成任务，任务ID：" + taskId);
 	}
	
	/**  
	* @Name: findHistoryProcessVariables（方法的名称）
	* @Description: 查询流程变量的历史表（方法的描述）
	* @Author: 李超（作者）
	* @Version: V1.00 （版本号）
	* @Create Date: 2016-12-12 （创建日期）
	* @Parameters: 无（方法的入参，如果没有，填写为“无”）
	* @Return: 无（返回值，如果没有，填写为“无”）
	*/
	@Test
	public void findHistoryProcessVariables() {
		List<HistoricVariableInstance> list = processEngine.getHistoryService()
					 .createHistoricVariableInstanceQuery() //创建一个历史流程变量查询对象
					 .variableName("请假天数")  //根据变量名称查询
					 .list() ; //返回查询集合
		if(list != null && list.size() > 0) {
			for (HistoricVariableInstance hvi : list) {
				System.out.println("流程变量ID:" + hvi.getId());
				System.out.println("流程实例ID:" + hvi.getProcessInstanceId()); 
				System.out.println("流程变量名称:" + hvi.getVariableName());
				System.out.println("流程变量类型:" + hvi.getVariableTypeName());
				System.out.println("流程变量的值:" + hvi.getValue());
				System.out.println("##########################################");
			}
		}
	}

}
